package com.model.demo.spring.framework.webmvc.servlet;

import com.model.demo.spring.framework.context.MyApplicationContext;
import com.model.demo.spring.mini.mvcframework.annotation.MyController;
import com.model.demo.spring.mini.mvcframework.annotation.MyRequestMapping;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class MyDispatcherServlet extends HttpServlet {

    private MyApplicationContext context ;

    private String LOCATION = "contextConfigLocation";

    private String TEMPLATE_ROOT= "templateRoot";

    private List<MyHandleMapping> handleMappings = new ArrayList<>();

    private Map<MyHandleMapping, MyHandlerAdapter> handleAdapter = new HashMap<MyHandleMapping, MyHandlerAdapter>();

    private List<MyViewResolve> viewResolves = new ArrayList<>();


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doDispatch(req, resp);

    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) {


        try {
            MyHandleMapping handler = getHandler(req);
            MyHandlerAdapter ha = getHandlerAdapter(handler);
            MyModelAndView mv = ha.handle(req, resp, handler);
            //这一步才是真的输出
            processDispatchResult(req,resp, mv);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    private void processDispatchResult(HttpServletRequest req, HttpServletResponse resp, MyModelAndView mv) throws Exception{
        if(mv == null){return;}
        if(viewResolves.isEmpty()){return;}
        for (MyViewResolve viewResolve : viewResolves) {
            MyView view = viewResolve.resolveViewName(mv.getViewName(), null);
            if(view!=null){
                view.render(mv.getModel(),req,resp);
            }
        }

    }

    private MyHandlerAdapter getHandlerAdapter(MyHandleMapping handler) {
       if(handleAdapter.isEmpty()){return null;}
        MyHandlerAdapter myHandlerAdapter = this.handleAdapter.get(handler);
       if(myHandlerAdapter.supports(handler)){
           return myHandlerAdapter;
       }
        return null;
    }

    private MyHandleMapping getHandler(HttpServletRequest req) {
        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+" , "/");
        if("".equals(url)){return null;}

        for (MyHandleMapping handle : handleMappings) {
            if(Pattern.matches(handle.getUrl().pattern(), url)){
                return handle;
            }
        }
        return null;
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        //1.初始化ApplicationContext,初始化容器
        context = new MyApplicationContext(config.getInitParameter(LOCATION));
        //2.初始化九大组件
        initStrategies(context);
    }

    private void initStrategies(MyApplicationContext context) {

        //多文件上传的组件
        initMultipartResolver(context);
        //初始化本地语言环境
        initLocaleResolver(context);
        //初始化模板处理器
        initThemeResolver(context);
        //handlerMapping(实现)
        initHandlerMappings(context);
        //初始化参数适配器(实现)
        initHandlerAdapters(context);
        //初始化异常拦截器
        initHandlerExceptionResolvers(context);
        //初始化视图预处理器
        initRequestToViewNameTranslator(context);
        //初始化视图转换器(实现)
        //通过 ViewResolvers 实现动态模板的解析
        //自己解析一套模板语言
        initViewResolvers(context);
        //快照参数管理
        initFlashMapManager(context);
    }







    private void initViewResolvers(MyApplicationContext context) {
        String templateRoot = context.getConfig().getProperty(TEMPLATE_ROOT);
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot).getFile();
        File file = new File(templateRootPath);
        for (File listFile : file.listFiles()) {
            this.viewResolves.add(new MyViewResolve(templateRoot));
        }



    }



    private void initHandlerAdapters(MyApplicationContext context) {
        for (MyHandleMapping handleMapping : handleMappings) {
            //每一个方法有一个参数列表，那么这里保存的是形参列表
            handleAdapter.put(handleMapping, new MyHandlerAdapter());
        }
    }

    private void initHandlerMappings(MyApplicationContext context) {
        String[] beanNames = context.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            Object bean = context.getBean(beanName);
            Class<?> clazz = bean.getClass();
            if(!clazz.isAnnotationPresent(MyController.class)|| !clazz.isAnnotationPresent(MyRequestMapping.class)){continue;}
            MyRequestMapping baseRoot = clazz.getAnnotation(MyRequestMapping.class);
            String baseRootPath = ("/" + baseRoot.value()).replaceAll("/+" ,"/");
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if(!method.isAnnotationPresent(MyRequestMapping.class)){continue;}
                String path = (baseRootPath + method.getAnnotation(MyRequestMapping.class).value()).replaceAll("\\*",
                        ".*").replaceAll("/+" ,"/");
                Pattern pattern = Pattern.compile(path);
                handleMappings.add(new MyHandleMapping(pattern, bean, method));
            }


        }

    }
    private void initRequestToViewNameTranslator(MyApplicationContext context) {

    }

    private void initHandlerExceptionResolvers(MyApplicationContext context) {


    }

    private void initThemeResolver(MyApplicationContext context) {

    }

    private void initLocaleResolver(MyApplicationContext context) {

    }

    private void initMultipartResolver(MyApplicationContext context) {
    }
    private void initFlashMapManager(MyApplicationContext context) {

    }
}
